﻿using System.Linq;
using ch08.binary.type;
using Microsoft.VisualBasic.CompilerServices;

namespace ch08.binary.interpreter
{
    public struct ControlStack
    {
        public ControlFrame[] Frames;


        public ControlStack(ControlFrame[] frames) : this()
        {
            Frames = frames;
        }

        internal void PushControlFrame(ref ControlFrame cf)
        {
            Frames = Frames.Append(cf).ToArray();
        }

        internal ControlFrame PopControlFrame()
        {
            var cf = Frames[^1];
            Frames = Frames.SkipLast(1).ToArray();
            return cf;
        }

        public int ControlDepth()
        {
            return Frames.Length;
        }

        public ControlFrame TopControlFrame()
        {
            return Frames[^1];
        }

        internal ( ControlFrame?, int) TopCallFrame()
        {
            for (var n = Frames.Length - 1; n >= 0; n--)
            {
                var cf = Frames[n];
                if (cf.Opcode == OpCodes.Call)
                {
                    return (cf, Frames.Length - 1 - n);
                }
            }

            return (null, -1);
        }
    }

    public unsafe struct ControlFrame
    {
        public readonly byte Opcode;
        public FuncType Bt; // block type
        public readonly Instruction[] Instrs; // expr
        public readonly int Bp; // base pointer (operand stack)
        public int Pc; // program counter

        public ControlFrame(byte opcode, ref FuncType bt, ref Instruction[] instrs, int bp)
        {
            this.Opcode = opcode;
            this.Bt = bt;
            this.Instrs = instrs;
            this.Bp = bp;
            this.Pc = 0;
        }
    }
}